# Specifické příkazy pro prostředí Google Colab
if 'google.colab' in str(get_ipython()):
import os, sys
os.chdir('/content')
# Stažení knihovny
! ls parlamentikon || git clone "https://github.com/parlamentikon/parlamentikon.git" --branch main
os.chdir('/content/parlamentikon/notebooks')
instalace_zavislosti = True
if instalace_zavislosti:
! pip install -r ../requirements.txt 1>/dev/null
instalace_knihovny = False
if instalace_knihovny:
! pip install .. 1>/dev/null
else:
# Přidání cesty pro lokální import knihovny
import sys, os
sys.path.insert(0, os.path.abspath('..'))
from datetime import datetime
import plotly.graph_objects as go
import pandas as pd
import numpy as np
from parlamentikon.Hlasovani import Hlasovani, ZpochybneniHlasovani, HlasovaniPoslanci
from nastav_notebook import nastav_pandas
# Data se budou pokaždé znovu stahovat z achivu PS
stahni=True
# Budeme analyzovat poslední volební období
zvolene_volebni_obdobi = None
# Načti souhrnné informace o hlasováních
h = Hlasovani(stahni=stahni, volebni_obdobi=zvolene_volebni_obdobi)
h.head(2)
# Načti informace o zpochybnění hlasování
zph = ZpochybneniHlasovani(stahni=stahni, volebni_obdobi=zvolene_volebni_obdobi)
zph.head(2)
# Načti indiviuální hlasování poslanců
hp = HlasovaniPoslanci(stahni=stahni, volebni_obdobi=zvolene_volebni_obdobi)
hp.head(2)
volebni_obdobi = h.volebni_obdobi
snemovna = h.snemovna
print(f"Poslanecká sněmovna bude analyzovaná pro volební období {volebni_obdobi}.")
Přibližná pravidla pro určení platnosti hlasování:
def flatten(ary):
return [x for l in ary for x in l]
# Hlasování o zpochybnění hlasování je možné také zkazit nebo zpochybnit.
# Mezi prvním hlasováním o zpochybnění a opakovaným hlasováním může proběhnout několik dalších zpochybněných nebo neplatných hlasování.
def fce_mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovanim_ids(row):
if pd.isna(row['id_h2']):
return []
elif pd.isna(row['id_h3']):
return []
else:
return list(range(row['id_h2']+1, row['id_h3']))
zpochybneni = zph[zph.je_platne == True]
mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovani_ids = \
flatten(zpochybneni[zpochybneni.mode__KAT == 'žádost o opakování'].apply(fce_mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovanim_ids, axis=1))
hlasovani_o_zpochybneni_ids = h[h.id_hlasovani.isin(zpochybneni.id_h2.unique())]
hlasovani_bez_zmatecnych_a_zpochybnenych = h[~h.je_zmatecne
& ~h.id_hlasovani.isin(zph[zph.mode__KAT == 'žádost o opakování'].id_hlasovani)
& ~h.id_hlasovani.isin(mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovani_ids)
& ~h.id_hlasovani.isin(hlasovani_o_zpochybneni_ids)
]
hlasovani_bez_zmatecnych_a_zpochybnenych.groupby('nazev_dlouhy').size().sort_values()
%%time
from collections import OrderedDict
# Vyber jenom platná hlasování
h_platne = hlasovani_bez_zmatecnych_a_zpochybnenych #[hlasovani_bez_zmatecnych_a_zpochybnenych.nazev_dlouhy == 'Novela z. o evidenci tržeb - EU']
df = hp[hp.id_hlasovani.isin(h_platne.id_hlasovani)]
# Seřaď osoby podle posl. klubu a shlukni hlasování podle osoby
data = df[['id_osoba', 'id_hlasovani', 'vysledek', 'zkratka_klub']]\
.set_index('id_osoba')\
.sort_values(by=['zkratka_klub'])[['id_hlasovani', 'vysledek']]\
.groupby('id_osoba', sort=False)\
.apply(lambda g: list(map(tuple, g.values))).to_dict(into=OrderedDict)
# Vyber informace k dané osobě. Bereme v úvahu poslední klub, do kterého poslanec/kyně patří.
osoby = {id_osoba: hp[hp.id_osoba == id_osoba][['jmeno', 'prijmeni', 'zkratka_kandidatka','nazev_kraj_cz', 'zkratka_klub']].iloc[-1] for id_osoba in data.keys()}
# Pro každou osobu připrav pole výsledků hlasování
hlasovani_osoby = {osoba: set([str(hl_idx) + '_' + vysledek for hl_idx, vysledek in data[osoba]]) for osoba in data.keys()}
%%time
def jaccard_similarity(set1, set2):
intersection_size = len(set1.intersection(set2))
union = len(set1) + len(set2) - intersection_size
return float(intersection_size) / union
matice_poslanci = {}
for osoba1, v1 in hlasovani_osoby.items():
if osoba1 not in matice_poslanci:
matice_poslanci[osoba1] = {}
for osoba2, v2 in hlasovani_osoby.items():
similarity = jaccard_similarity(v1, v2)
matice_poslanci[osoba1][osoba2] = similarity
osoby_data = pd.DataFrame([
{
'jmeno_prijmeni': f"{osoby[id_osoba].jmeno} {osoby[id_osoba].prijmeni}",
'id_osoba': id_osoba,
'zkratka_klub': osoby[id_osoba].zkratka_klub
}
for id_osoba in matice_poslanci.keys()
])
osoby_data['velikost_skupiny'] = osoby_data.groupby('zkratka_klub').id_osoba.transform(len)
osoby_data['poradi_v_skupine'] = osoby_data.groupby('zkratka_klub').cumcount() + 1
osoby_data['je_na_okraji'] = (osoby_data.poradi_v_skupine == 1) | (osoby_data.velikost_skupiny == osoby_data.poradi_v_skupine)
osoby_data['je_uprostred'] = osoby_data.poradi_v_skupine == (osoby_data.velikost_skupiny/2).astype(int)
text = [
[
f"{v1.jmeno_prijmeni} ({v1.zkratka_klub})<br>"
f"{v2.jmeno_prijmeni} ({v2.zkratka_klub})<br>"
f"Podobnost hlasování: {100*matice_poslanci[v1.id_osoba][v2.id_osoba]:.0f}%" for idx2, v2 in osoby_data.iterrows()
] for idx1, v1 in osoby_data.iterrows()
]
fig = go.Figure(data=go.Heatmap(
z=pd.DataFrame(matice_poslanci),
x=osoby_data.id_osoba.values,
y=osoby_data.id_osoba.values,
text=text,
colorscale='Viridis',
hovertemplate="%{text}<extra></extra>"
))
fig.update_layout(title='Podobnost hlasování poslanců', width=1000, height=1000)
#fig.update_xaxes(type='category', tickangle=45, tickmode='array', ticktext=label_strana, tickvals=label)
for zkratka_klub in osoby_data.zkratka_klub.unique():
fig.update_xaxes(
type='category', tickangle=-45,
side='top', overlaying='x',
tickmode='array', ticktext=osoby_data[osoby_data.je_uprostred].zkratka_klub, tickvals=osoby_data[osoby_data.je_uprostred].id_osoba,
showspikes=True,
spikemode='toaxis'
)
fig.update_yaxes(
type='category', autorange='reversed',
tickmode='array', ticktext=osoby_data[osoby_data.je_uprostred].zkratka_klub, tickvals=osoby_data[osoby_data.je_uprostred].id_osoba,
showspikes=True,
spikemode='toaxis'
)
fig.show()
matice_kluby = {}
for id_osoba1, values in matice_poslanci.items():
klub1 = osoby[id_osoba1].zkratka_klub
if klub1 not in matice_kluby:
matice_kluby[klub1] = {}
for id_osoba2, podobnost in values.items():
klub2 = osoby[id_osoba2].zkratka_klub
if klub2 not in matice_kluby[klub1]:
matice_kluby[klub1][klub2] = []
matice_kluby[klub1][klub2].append(podobnost)
matice_kluby_median = pd.DataFrame({ klub1: {klub2: np.median(ary) for klub2, ary in values.items()} for klub1, values in matice_kluby.items()})
matice_kluby_prumer = pd.DataFrame({ klub1: {klub2: np.mean(ary) for klub2, ary in values.items()} for klub1, values in matice_kluby.items()})
fig = go.Figure(data=go.Heatmap(
z=matice_kluby_prumer,
x=list(matice_kluby_prumer.keys()),
y=list(matice_kluby_prumer.keys()),
colorscale='Viridis',
hovertemplate="%{x}<br>%{y}<br>Podobnost hlasování: %{z}<extra></extra>"
))
fig.update_layout(
title='Podobnost hlasování dle poslaneckých klubů',
width=800,
height=800,
autosize=False,
margin=dict(t=150, b=0, l=0, r=0),
template="plotly_white",
)
fig.update_xaxes(
type='category', tickangle=-45,
side='top',
)
fig.update_yaxes(
type='category', autorange='reversed',
)
updatemenus = [{
'buttons': [
{'method': 'update', 'label': 'průměr', 'args': [{'z': [matice_kluby_prumer.values]}]},
{'method': 'update', 'label': 'medián', 'args': [{'z': [matice_kluby_median.values]}]}
],
'direction': 'down',
'showactive': True,
'x': 1.1, 'xanchor': 'right', 'y': 1.15, 'yanchor': 'top',
}]
# update layout with buttons, and show the figure
fig.update_layout(updatemenus=updatemenus)
fig.show()
print(f"Poslední běh notebooku: {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}.")